﻿using System.Collections.Generic;
using System.ComponentModel;
using StepsManagerLibrary.Annotations;
using StepsManagerLibrary.Enum;
using StepsManagerLibrary.Events;
using StepsManagerLibrary.Interfaces;
namespace StepsManagerUILibrary
{
    /// <summary>
    /// This class is shared accross the UI UserControl so that it 
    /// </summary>
    internal class BaseStepControl : IStepControl
    {
        #region Fields

        private readonly string _title;
        private StepControlStateEnum _state;

        private readonly IList<IObserver<StepControlStateEnum>> _observers;

        #endregion

        #region Constructors

        public BaseStepControl()
            : this("")
        {
        }

        public BaseStepControl(string title)
        {
            _title = title ?? "";
            _state = StepControlStateEnum.NotSelected;
            _observers = new List<IObserver<StepControlStateEnum>>();
        }

        #endregion

        #region Members of IStepControl

        public virtual string Title
        {
            get { return _title; }
        }

        public virtual StepControlStateEnum State 
        {
            get { return _state; }
            set
            {
                if (_state != value)
                {
                    // Updating the current value
                    _state = value;
                    
                    // Notifying the listeners
                    Notify(_state);

                    OnPropertyChanged("State");
                }
            }
        }

        #region Initialization
        
        public virtual bool Initialize()
        {
            return true;
        } 

        #endregion

        #region Navigation Checks
        public virtual bool CanMoveIn()
        {
            return true;
        }

        public virtual bool CanMoveOut()
        {
            return true;
        } 
        #endregion

        #region Navigation
        
        public virtual bool BeforeMovingIn()
        {
            return true;
        }

        public virtual bool MoveIn()
        {
            return true;
        }

        public virtual bool AfterMovingIn()
        {
            return true;
        }

        public virtual bool BeforeMovingOut()
        {
            return true;
        }

        public virtual bool MoveOut()
        {
            return true;
        }

        public virtual bool AfterMovingOut()
        {
            return true;
        } 

        #endregion

        #region IStepControl.IObservable<T> Members
        
        public virtual void Attach(IObserver<StepControlStateEnum> observer)
        {
            _observers.Add(observer);
        }

        public virtual void Detach(IObserver<StepControlStateEnum> observer)
        {
            _observers.Remove(observer);
        }

        public virtual void Notify(StepControlStateEnum notification)
        {
            if (_observers == null)
                return;

            foreach (IObserver<StepControlStateEnum> observer in _observers)
            {
                observer.Notify(notification);
            }
        }

        #endregion

        #region IStepControl.IObserver<T, U> Members

        ///// <summary>
        ///// The object is being notified that an Action wants to be done
        ///// </summary>
        ///// <param name="notificationType"></param>
        //public void Notify(StepActionEnum notificationType, object parameter)
        //{
        //    // The object can be notified by its Observers that they expect
        //    // Some changes around
        //    throw new System.NotImplementedException();
        //}

        #endregion

        #region Members of IStepControl.INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region IActionInitiator Members

        /// <summary>
        /// Start an action
        /// </summary>
        /// <param name="actionType">Type of the action</param>
        /// <param name="args">Parameters required to perform the action</param>
        public bool StartAction(StepActionTypeEnum actionType, ActionEventArgs args)
        {
            OnActionExpected(actionType, args);

            return true;
        }

        #endregion

        public event ActionExpectedEventHandler ActionExpected;

        /// <summary>
        /// Firing an event that inform that an Action has been required from
        /// the current IStepControl
        /// </summary>
        /// <param name="actionType"></param>
        /// <param name="args">Arguments related with the action</param>
        protected virtual void OnActionExpected(StepActionTypeEnum actionType, 
            ActionEventArgs args)
        {
            ActionExpectedEventHandler handler = ActionExpected;

            if (handler != null)
            {
                handler(this, actionType, args);
            }
        }

        #endregion
    }
}
